package logger

import (
	"encoding/json"
	"fmt"
	"me.qqtu.game/logger/gelf"
	"os"
	"sync"
	"time"
)

type Extras map[string]interface{}

const (
	Emergency uint8 = 0
	Alert     uint8 = 1
	Critical  uint8 = 2
	Error     uint8 = 3
	Warning   uint8 = 4
	Notice    uint8 = 5
	Info      uint8 = 6
	Debug     uint8 = 7
)

var (
	ins *Logger
)

func InitLogger(source string, host string, port string) {
	ins = &Logger{}
	ins.Source = source
	ins.Host = host
	ins.Port = port
	ins.MaxLevel = Debug

	w, err := gelf.NewWriter(host + ":" + port)
	if err == nil {
		ins.Writer = w
	}
}

func GetLogger() *Logger {
	return ins
}

//------------------------------------------------------------

type Logger struct {
	Source   string
	Host     string
	Port     string
	Writer   *gelf.Writer
	MaxLevel uint8
	sync.Mutex
}

func (logger *Logger) Log(level uint8, message string, extras Extras) error {
	if logger.Writer != nil {
		msg := new(gelf.Message)
		msg.Version = "1.1"
		msg.Host = logger.Source
		msg.Short = message
		msg.TimeUnix = time.Now().Unix()
		msg.Level = level
		if extras != nil {
			outExtras := make(map[string]interface{})
			for k, _ := range extras {
				if k == "_id" {
					continue
				} else if k[0] == '_' {
					outExtras[k] = extras[k]
				} else {
					outExtras["_"+k] = extras[k]
				}
			}
			msg.Extra = outExtras
		} else {
			msg.Extra = make(map[string]interface{})
		}

		b, err := msg.MarshalJSON()

		if err != nil {
			return err
		}
		logger.Writer.WriteMessage(b)
	}
	//print
	var levelStr string = "Unknow"
	switch level {
	case Emergency:
		levelStr = "Emergency"
	case Alert:
		levelStr = "Alert"
	case Critical:
		levelStr = "Critical"
	case Error:
		levelStr = "Error"
	case Warning:
		levelStr = "Warning"
	case Notice:
		levelStr = "Notice"
	case Info:
		levelStr = "Info"
	case Debug:
		levelStr = "Debug"
	}
	if extras != nil {
		extraStr, _ := json.Marshal(extras)
		fmt.Println("[" + time.Now().String() + "] [" + levelStr + "] message:" + message + ",data:" + string(extraStr))
	} else {
		fmt.Println("[" + time.Now().String() + "] [" + levelStr + "]message:" + message)
	}
	return nil
}

func (logger *Logger) Emergency(message string, extras Extras) error {
	return logger.Log(Emergency, message, extras)
}

func (logger *Logger) Alert(message string, extras Extras) error {
	return logger.Log(Alert, message, extras)
}

func (logger *Logger) Critical(message string, extras Extras) error {
	return logger.Log(Critical, message, extras)
}

func (logger *Logger) Error(message string, extras Extras) error {
	return logger.Log(Error, message, extras)
}

func (logger *Logger) Warning(message string, extras Extras) error {
	return logger.Log(Warning, message, extras)
}

func (logger *Logger) Notice(message string, extras Extras) error {
	return logger.Log(Notice, message, extras)
}

func (logger *Logger) Info(message string, extras Extras) error {
	return logger.Log(Info, message, extras)
}

func (logger *Logger) Debug(message string, extras Extras) error {
	return logger.Log(Debug, message, extras)
}

func (logger *Logger) HandlePanic() {
	if r := recover(); r != nil {
		logger.Error("Fatal error", Extras{"error": r})
		os.Exit(1)
	}
}
